package de.koller.million.grid;

import de.koller.aframe.util.thread.ICommand;
import de.koller.aframe.util.thread.ILoopHandler;
import de.koller.aframe.util.thread.ThreadRootHandle;

public class GLoop implements ILoopHandler {

	public final int UPDATE_TIME = 100;
			
	private final GridRoot root;
	public final ThreadRootHandle thread = new ThreadRootHandle( "loop" );
	
	private int cps;
	private int currCps;
	private long nextCps;
	
	private long nextLog;
	private long currCalcTime;
	private int currCalcStep;
	
	private boolean running = false;
	
	public GLoop( GridRoot root ) {
		this.root = root;
	}

	public void begin() {
		thread.setLoopHandler( this );
		running = true;
		thread.start();
	}
	
	public void stop() {
		thread.stop();
		running = false;
	}
	
	private void loop() {	
		long delta = 0;
		long lastTime = System.currentTimeMillis();
		long unprocessed = 0;
		
		root.initalize();
		
		while( running ) {
			long currtime = System.currentTimeMillis();
			delta = currtime - lastTime;
			lastTime = currtime;
			
			unprocessed += delta;
			if( unprocessed == 0 )
				continue;
			
			if( unprocessed < UPDATE_TIME ) {
				Thread.yield();
				continue;
			}
			
			long ct = System.nanoTime();
			unprocessed -= UPDATE_TIME;
			if( thread.hasCommands() ) {
				ICommand cmd = this.thread.pop();
				cmd.handle();
			}
			
			root.updating( UPDATE_TIME );
			root.rendering( UPDATE_TIME );
			
			checkCps( currtime );
			log( currtime, System.nanoTime() - ct );
		}
		
		root.releasing();
	}

	private void log( long currtime, long calctime ) {
		currCalcTime += calctime;
		currCalcStep++;
		
		if( nextLog < currtime ) {
			double st = currCalcTime / currCalcStep;
			st /= 1_000_000;
			st = Math.round( st );
			st /= 1000;
			
			long space = Math.round( (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024. / 1024. );
			
			System.out.println( "10sec log: " + currCalcStep + " steps (=" + st
					+ "ms [" + currCalcStep/10 + "]) " + space + "MB" );
			currCalcTime = 0;
			currCalcStep = 0;
			nextLog = currtime + 10_000;
		}
	}
	
	private void checkCps( long currtime ) {
		if( nextCps < currtime ) {
			cps = currCps;
			currCps = 0;
			nextCps = currtime + 1_000;
		}

		currCps++;
	}
	
	@Override
	public void loopHandle() {
		loop();
	}
	
}
